import { createStore, ObservableMap, Subscription } from '@stencil/store';

/**
 * 数据状态存储
 *
 * @author chitanda
 * @date 2021-06-30 17:06:41
 * @export
 * @abstract
 * @class StoreBase
 * @template State
 */
export abstract class StoreBase<State = any> {
  /**
   * 存储
   *
   * @protected
   * @type {ObservableMap<State>}
   * @memberof IBzResourceAllocationStore
   */
  protected store: ObservableMap<State>;
  /**
   * 事件缓存
   *
   * @author chitanda
   * @date 2021-06-30 17:06:39
   * @protected
   * @type {Map<any, any>}
   */
  protected evtCache: Map<any, any> = new Map();

  /**
   * 状态
   *
   * @type {State}
   * @memberof IBzResourceAllocationStore
   */
  readonly data: State;

  /**
   * Creates an instance of StoreBase.
   *
   * @author chitanda
   * @date 2021-06-30 18:06:21
   * @param {State} [state=Object.create({})]
   */
  constructor(state: State = Object.create({})) {
    this.store = createStore<State>(state);
    this.data = this.store.state;
    this.store.on;
  }

  /**
   * 将状态重置为其原始状态
   *
   * @author chitanda
   * @date 2021-06-30 18:06:37
   */
  reset(): void {
    this.store.reset();
  }

  /**
   * 将状态重置为其原始状态，并删除全部事件订阅、向所有插件发送dispose事件信号。
   *
   * @author chitanda
   * @date 2021-06-30 18:06:01
   */
  dispose(): void {
    this.store.dispose();
    this.eventReset();
  }

  /**
   * 强制重新输入指定的键，就像更改了值一样
   *
   * @author chitanda
   * @date 2021-06-30 18:06:27
   * @param {keyof State} key
   * @return {*}  {void}
   */
  forceUpdate(key: keyof State): void {
    return this.store.forceUpdate(key);
  }

  /**
   * 注册用户获取、设置或重置值时将调用的订阅
   *
   * @author chitanda
   * @date 2021-06-30 18:06:52
   * @param {...Subscription<State>[]} plugins
   */
  use(...plugins: Subscription<State>[]): void {
    this.store.use(...plugins);
  }

  /**
   * 订阅事件
   *
   * @template K
   * @param {K} name
   * @param {(arg?: State[K]) => void} cb
   * @memberof StoreBase
   */
  on(name: 'dispose', cb: () => void): void;
  on(name: 'reset', cb: () => void): void;
  on<K extends keyof State>(name: K, cb: (arg?: State[K]) => void): void;
  on<K extends keyof State>(name: K, cb: (arg?: State[K]) => void): void {
    const fn = this.store.onChange(name, cb);
    this.evtCache.set(cb, fn);
  }

  /**
   * 取消订阅事件
   *
   * @template K
   * @param {(arg?: State[K]) => void} cb
   * @memberof StoreBase
   */
  off<K extends keyof State>(cb: (arg?: State[K]) => void): void {
    if (this.evtCache.has(cb)) {
      const fn = this.evtCache.get(cb);
      fn();
      this.evtCache.delete(cb);
    }
  }

  /**
   * 重置事件
   *
   * @author chitanda
   * @date 2021-06-30 18:06:17
   * @protected
   */
  protected eventReset(): void {
    this.evtCache.forEach(fn => {
      fn();
    });
    this.evtCache.clear();
  }
}
